// 本文件用于制定应用层协议，让client和server达成共识
#pragma once
#include <iostream>
#include <memory>
#include <string>
#include <jsoncpp/json/json.h> //使用json的序列化反序列化方案

const std::string separator = " ";
const std::string flag = "\n";

//添加报文边界 "res stat" -> "len\nres stat\n" || "x op y" -> "len\nx op y\n"
void AddMargins(std::string& message)
{
    std::string len = std::to_string(message.size());
    message = len + flag + message + flag;
}

//去掉报文边界 "len\nres stat\n" -> res stat" || "len\nx op y\n" -> "x op y"
bool DelMargins(std::string& new_datagram, std::string& datagram)
{
    //这里需要注意,我们无法保证datagram就是一个完整的报文
    // l
    // len
    // len\nr
    // len\nres stat
    // len\nres stat\n
    // len\nres stat\nlen\nres
    // len\nres stat\nlen\nres stat\n
    // 所以这里我们先要对报文进行检测
    
    // 1. 检测报文是否是一个完整报文
    // 检测是否能读完len
    int pos = new_datagram.find(flag);
    if( pos == std::string::npos) 
    {
        std::cout << "if( pos == std::string::npos) " << std::endl;
        return false;
    }

    // 一定读到了len，再进而判断是否读到了完整的报文
    int len = std::stoi(new_datagram.substr(0, pos));
    if(len < new_datagram.size() - pos - flag.size() * 2)
     {
        std::cout << " if(len < new_datagram.size() - pos + flag.size() * 2) " << std::endl;
        return false;
     }

    // 2. 一定读到了完整的报文，拿出有效载荷
    new_datagram = new_datagram.substr(pos + flag.size(), len);

    // 3. 删除一个报文的长度
    datagram.erase(datagram.begin(), datagram.begin() + pos + len + flag.size() * 2);

    return true;
}

// 请求方client
class Request
{
public:
    Request()
        : _data_x(0), _data_y(0), _oper(0)
    {
    }

    Request(int data_x, int data_y, char oper)
        : _data_x(data_x), _data_y(data_y), _oper(oper)
    {
    }

    ~Request()
    {
    }

    // 序列化，将结构化数据 -> "x op y"
    std::string Serialize()
    {
#ifdef MySerialize    //定义MySerialize这个宏，就使用我们自己的序列化和反序列化方法
        std::string ser_str = std::to_string(_data_x) + separator + _oper + separator + std::to_string(_data_y);
        return ser_str;
#else
        //使用json方法
        // 1. 构建键值对
        Json::Value root;
        root["data_x"] = _data_x;
        root["data_y"] = _data_y;
        root["oper"] = _oper;
        // 序列化
        Json::FastWriter writer;
        std::string ser_str = writer.write(root);
        return ser_str;
#endif

    }
    // 反序列化，将"x op y" -> 结构化数据
    void Deserialize(std::string message)
    {
#ifdef MySerialize    //定义MySerialize这个宏，就使用我们自己的序列化和反序列化方法
        // 拿x
        auto pos = message.find(separator);
        _data_x = std::stoi(message.substr(0, pos)); //[)
        // 拿oper
        _oper = *(message.substr(pos + separator.size(), 1).c_str());
        // 拿y
        auto rpos = message.rfind(separator);
        _data_y = std::stoi(message.substr(rpos + separator.size()));
#else               //没有定义，就使用json这个方法
        // 1. 构建键值对
        Json::Value root;
        // 2. 反序列化
        Json::Reader reader;
        reader.parse(message, root);
        // 3. 恢复结构化数据
        _data_x = root["data_x"].isInt();
        _data_y = root["data_y"].isInt();
        _oper = root["oper"].isInt();
#endif
    }

    int GetData_X() { return _data_x; }
    int GetData_Y() { return _data_y; }
    char GetOper() { return _oper; }

private:
    int _data_x;
    int _data_y;
    char _oper;
};

// 响应方server
class Response
{
public:
    Response()
        : _result(0), _stat(0)
    {
    }
    Response(int result, int stat)
        : _result(result), _stat(stat)
    {
    }

    
    const Response& operator=(const Response& another)
    {
        if(this != &another)
        {
            _result = another._result;
            _stat = another._stat;
        }
        return *this;
    }

    ~Response() {}

    // 序列化，将结构化数据 -> "res stat"
    std::string Serialize()
    {
#ifdef MySerialize    //定义MySerialize这个宏，就使用我们自己的序列化和反序列化方法   
        std::string ser_str = std::to_string(_result) + separator + std::to_string(_stat);
        return ser_str;
#else
        // 构建->键值对[K, V] 
        // K必须是可以转换成字符串类型的数据类型
        // V可以是任意类型，底层使用的是union类型支持的，这就要求拿出来的时候要做类型转换
        // 在Value内部提供了转换函数
        Json::Value root;
        root["result"] = _result; //
        root["stat"] = _stat;
        // 使用json的序列化方法 -> {"result":_result, "stat":_stat}
        Json::FastWriter writer; //这里也可以使用StyledWriter，就是两种不同的序列化方法，构建成的字符串形式不同，在底层使用了多态，都继承了Writer这个抽象类
        std::string ser_str = writer.write(root);
        return ser_str;
#endif
    }
    
    // 反序列化，将"res stat" -> 结构化数据
    void Deserialize(std::string message)
    {
#ifdef MySerialize    //定义MySerialize这个宏，就使用我们自己的序列化和反序列化方法
        // 拿result
        auto pos = message.find(separator);
        _result = std::stoi(message.substr(0, pos)); //[)
        // 拿stat
        _stat = std::stoi(message.substr(pos + separator.size()));
#else                 //没有定义就使用json方案
        // 1. 构建->键值对
        Json::Value root;
        // 2. 使用json的反序列化方法
        Json::Reader reader;
        reader.parse(message,root); // {"result":_result, "stat":_stat} -> ["result", _result], ["stat", _stat]
        // 3. 恢复结构化数据
        _result = root["result"].asInt(); //将union类型转换为int
        _stat = root["stat"].asInt();
#endif
    }

    int GetResult() { return _result; }
    int GetStat() { return _stat; }

private:
    int _result;
    int _stat; // 运算状态
};

// 设计模式：工厂模式，建造类设计模式
class Factory
{
public:
    std::shared_ptr<Request> BuildRequest()
    {
        return std::make_shared<Request>();
    }
    std::shared_ptr<Request> BuildRequest(int data_x, int data_y, char oper)
    {
        return std::make_shared<Request>(data_x, data_y, oper);
    }
    std::shared_ptr<Response> BuildResponse()
    {
        return std::make_shared<Response>();
    }
    std::shared_ptr<Response> BuildResponse(int result, int stat)
    {
        return std::make_shared<Response>(result, stat);
    }
};
